#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <unistd.h>
#include <string.h>
#include "util.h"
#include "contenttype.h"
#include "convert.h"
#include "buffer.h"

char*     
fields_get_pair(char*   data, char  *key, char  *value, char  *defkey)
{
    char    *start;
    char    *line;
    int     i;
    char    ch;

    if (NULL == data)
        return data;

    line = data;
    i = 0;
    // 跳过:, 但不能有; "
    while (*line != ':')
    {
        if (*line == ';' || *line == '\"')
        {
            line = data;
            break;
        }
        line++;
    }
    
    if (*line == ':')
        start = line + 1;
    else
        start = line;


    while (*line != '\0')
    {
        // 注意这种形式: name*=gb2312'zh_cn'xxxxxxxxxxxxxxx
        if (*line == '=')
        {
            while(start < line)
            {
                if (*start != ' ')
                {
                    if (*start >= 'A' && *start <='Z')
                        ch = *start + 32;
                    else
                        ch = *start;
                    key[i] = ch;
                }
                i++;
                start++;
            }
            key[i] = 0;
            line++;
            while ((*line == ' ') || (*line == '\"'))line++;
            i = 0;
            while ((*line != '\"') && (*line != ';') && (*line != '\0'))
            {
                if (*line >= 'A' && *line <= 'Z')
                    ch = *line + 32;
                else
                    ch = *line;
                value[i] = ch;
                i++;
                line++;
            } 
            value[i] = 0;
            if (*line == '\"')line += 2;
            else if (*line != ';')line++;
            break;
        }else if (*line == ';'){
            char    *end;
            i = 0;
            end = line - 1;
            while (*start == ' ') start++;
            while (*end == ' ') end--;
            while (start <=  end)
            {
                if (*start >= 'A' && *start <='Z')
                    ch = *start + 32;
                else
                    ch = *start;

                value[i] = ch;
                i++;
                start++;
            } 
            value[i] = 0;
            strcpy(key, defkey);
            line++;
            break;
        }
        line++;
    }

    return  line;
}


int     
fields_get_pairs(char* data, char  *defkey, void *obj, 
                 int (*obj_set)(void* fobj,char*key,char*value) )
{
    char    *start;
    char    *line;
    char    key[512];
    char    value[1024];
    int     i;
    char    ch;

    if (NULL == data)
        return -1;
    if (NULL == obj_set)
        return -3;

    i = 0;
    line = strchr(data, ':');
    if (NULL == line) {
        line = data;
        start = line;
    }else{
        start = data;
        while (start < line) {
            if (*start == '"' || *start == '=' || *start == ';' || *start == '/')
                break;
            start++;
        }
        //INFO("start pos:%c\n", *start);
        if (start < line) {
            start = data;
            line = data;
        }else{
            start = line;
        }
    }
    // 跳过:
    line++;

    //INFO("line=%s\n", line);
    while (*line != '\0') {
        // 注意这种形式: name*=gb2312'zh_cn'xxxxxxxxxxxxxxx
        if (*line == '=') {
            i = 0;
            while (*start <= 32) start++;
            while(start < line) {
                if (*start != ' ') {
                    if (*start >= 'A' && *start <= 'Z')
                        ch = *start + 32;
                    else
                        ch = *start;
                    key[i] = ch;
                }
                i++;
                start++;
            }
            key[i] = 0;
            // 查找value
            line++;
            while ((*line == ' ') || (*line == '\"') || (*line== '\n'))line++;
            i = 0;
            while ((*line != '\"') && (*line != ';') && (*line != '\0')) {
                // base64编码是区分大小写的，如果全部转换为小写就不能正确解码\
                // 但是的注意boundary在处理时是不区分大小写的
                /*
                if (*line >= 'A' && *line <= 'Z')
                    ch = *line + 32;
                else
                    ch = *line;
                value[i] = ch;
                */

                value[i] = *line;
                i++;
                line++;
            } 
            value[i] = 0;
            if (obj_set != NULL)
                obj_set(obj, key, value);

            while (*line == '\"' || *line == ';') {
                line++;
            }
            start = line;
            //INFO("1 key=%s, value=%s\n", key, value);
        }else if (*line == ';'){
            char    *end;
            i = 0;
            end = line;
            while (*start <= 32) start++;
            while (*end <= 32) end--;
            while (start <=  end) { 
                // 象 content-type: text/plain; boundary="xxxxxxxxxxxxxxxxxx" 这样的，第一个转换为小写应该也没有问题
                if (*start >= 'A' && *start <= 'Z')
                    ch = *start + 32;
                else
                    ch = *start;

                value[i] = ch;
                i++;
                start++;
            } 
            value[i] = 0;
            strcpy(key, defkey);
            if (obj_set != NULL)
                obj_set(obj, key, value);
            line++;  // skip ;
            while (*line == '\n' || *line == '\r' || *line == ' ' || *line == '\t') {
                line++;
            }
            start = line;
            //INFO("2 key=%s, value=%s\n", key, value);
        }
        if (*line != '\0')
            line++;
    }
    return 0;
}


int
fields_get_pairs_recv(char* data, void *obj, int (*obj_set)(void* obj,char*key,char*value) )
{
    //int     maxlen = 4;
    char    *line;
    char    buffer[512];
    char    okey[5];
    char    ch;
    int     i, haskey;  // 是否已经有过关键字了
    char    *start, *end;

    if (NULL == data)
        return -1;

    line = data;
    i = 0;
    while ((*line != ':') && (*line != '\0'))line++;

    if (*line == ':')
    {
        line++;
    }else if (*line == '\0'){
        return -2;
    }else{
        line = data;
    }
    haskey = 0; 
    okey[0] = 0;
    start = line;
    while (*line != '\0')
    {
        //printf("*line=%c %d\n", *line, *line);
        while((*line == ' ') || *line == '\t')line++;         
        i = 0;
        while (*line != ' ' && *line != '\t' && *line != ';' && *line != '\0')
        {
            if (*line >= 'A' && *line <= 'Z')
                ch = *line + 32;
            else
                ch = *line;
            buffer[i] = ch;
            i++;
            line++;
        }
        buffer[i] = 0;
        //printf("111 buffer: %s\n", buffer);
        if (*line == ';')
        {
            end = line;
            i = 0;
            while (start < end)
            {
                if (*start >= 'A' && *start <= 'Z')
                    ch = *start + ch;
                else
                    ch = *start;
                buffer[i] = ch; 
                i++;
                start++;
            }

            //printf("3 value: %s\n", buffer);
            buffer[i] = 0;
            if (obj_set)
                obj_set(obj, okey, buffer);
            line++; 
            while (*line == '\r' || *line == '\n' || *line == ' ' || *line == '\t')line++;

            strcpy(okey, "date");
            i = 0;
            while (*line != '\n' && *line != '\0')
            {
                buffer[i] = *line;
                i++;
                line++;
            }
            buffer[i] = 0;
        
            //printf("2 key: %s\n", okey);
            //printf("2 value: %s\n", buffer);
            if (obj_set)
                obj_set(obj, okey, buffer);
            break;
        }/*else{
            if (*line != 0)
                line++;
        }*/
        //printf("buffer: %s\n", buffer);
        if (i <= 4)
        {
            int     iskey = 1;
            char    keybak[5] = {0};

            strcpy(keybak, okey);
            if (strcmp(buffer, "from") == 0)
            {
                strcpy(okey, "from");
            }else if (strcmp(buffer, "by") == 0){
                strcpy(okey, "by");
            }else if (strcmp(buffer, "for") == 0){
                strcpy(okey, "for");
            }else if (strcmp(buffer, "via") == 0){
                strcpy(okey, "via");
            }else if (strcmp(buffer, "with") == 0){
                strcpy(okey, "with");
            }else if (strcmp(buffer, "id") == 0){
                strcpy(okey, "id");
            }else{
                iskey = 0;
            }
            //if (okey != NULL)
            if (iskey == 1)
            {
                if (haskey != 0)
                {
                    end = line - i;
                    i = 0;
                    while (start < end)
                    {
                        buffer[i] = *start; 
                        i++;
                        start++;
                    }
                    buffer[i] = 0;
                    //printf("1 key: %s\n", okey);
                    //printf("1 value: %s\n", buffer);
                    if (obj_set)
                        obj_set(obj, keybak, buffer);
                }
                while (*line == '\r' || *line == '\n' || *line == ' ' || *line == '\t')line++;
                start = line;
                
                haskey = 1;
            }
        }else{
            if (haskey == 0)
                strcpy(okey, "by");
        }
        if (line)
            line++;
    }
    

    return 0;
}

/*!
 把 AAAA: BBBBB 这样的以:分开
 */
int     
fields_split(char *data, int len, void *obj, int (*obj_set)(void *fobj, char* key, char *value, int valen))
{
    char    *start;
    char    okey[256+1], *value;
    char    ch;
    int     vlen, i;
    
    if (NULL == data)
        return -1;

    if (len <= 0)
        return -2; 

    //INFO("data: %p, len: %d\n", data, len); 
    ch = data[len];
    data[len] = 0;

    start = data;
    value = strchr(data, ':');
    //INFO("value: %s\n", value);
    data[len] = ch;
    if (NULL == value)
        return -3;

    vlen = value-start;
    if (vlen > 256 ) { // 信件头的字段名是不可能太长的。。
        return -4;
    }
    //INFO("vlen: %d\n", vlen);
    start = xstrnstrip(start, &vlen);
    //INFO("okey: %p, start: %p, vlen=%d\n", okey, start, vlen); 
    strncpy(okey, start, vlen);
    xstrnlower(okey, vlen);
    okey[vlen] = 0;
    
    start = strchr(okey, '*');
    if (NULL != start) {
        *start = 0;  
    }

    //INFO("key = %s\n", okey);
    value++; // 当前的:不能算
    vlen = len - (value-data); 
    //printf("value : %p, data: %p, vlen: %d\n", value, data, vlen);
    value = xstrnstrip(value, &vlen);
    

    if (obj_set)
        obj_set(obj, okey, value , vlen);
    return 0;
}

char*	xstrdup(const char* data)
{
    char    *ret;
    int     len = strlen(data); 

    ret = (char*)emalloc(len + 1);
    if (NULL == ret) {
        return NULL;
    }
    strncpy(ret, data, len);
    ret[len] = 0;
    return ret;

}

char*	xstrndup(const char* data, int len)
{
    char *ret;
    
    ret = (char*)emalloc(len + 1);
    if (NULL == ret) {
        return NULL;
    }
    strncpy(ret, data, len);
    ret[len] = 0;
    return ret;
}

char*	xstrsdup(const char* data, char *endstr, int len)
{
    char *ret = NULL;
    char *tmp = (char*)data;
    int  i, c = 0;
    
    while (*tmp) {
        
        for (i = 0; i< len; i++) {
            if (*tmp == endstr[i]) {
                break;
            }
        }

        if (i < len) {
            break;
        }else{
            c++;
        }
        tmp++;
    }
    
    if (c > 0) {
        ret = xstrndup(data, c);
    }

    return ret;
}

int 
xstrslen(const char *data, char *endstr, int len)
{
    char *tmp = (char*)data;
    int  i, c = 0;
    
    while (*tmp) {
        
        for (i = 0; i< len; i++) {
            if (*tmp == endstr[i]) {
                break;
            }
        }

        if (i < len) {
            break;
        }else{
            c++;
        }
        tmp++;
    }
    
    return c;
}


char*  xstrnstrip(char *data, int *len) 
{
    char    *ret;
    int     i, size;

    size = *len;
    ret = data;
    
    //INFO("data len: %d\n", size);
    for (i = 0; i < size; i++) {
        //INFO("front: %d\n", (unsigned int)data[i]);
        if ((unsigned int)data[i] > 32) // 双字节的中文字可能会让data[i]是负值，必须做类型转换
            break;
        ret++;
        (*len)--;
    }

    for (i = size-1; i>= 0; i--) {
        //INFO("backend: %d\n", (unsigned int)data[i]);
        if ((unsigned int)data[i] > 32)
            break;
        if (&data[i] == ret)
            break;
        (*len)--;
    }

    return ret;
}

void   
xstrnlower(char *data, int len)
{
    int  i;
    char ch;
    for (i = 0; i< len; i++) {
        ch = data[i];
        if (ch >= 'A' && ch <= 'Z') {
            data[i] = ch + 32;
            //printf("modify %c\n", data[i]);
        }
    }
}


char*   
xstrappend(char *dst, char *src, int srclen)
{
    char    *newstr;
    newstr = xstrappend_nofree(dst, src, srclen);
    if (NULL == newstr) {
        newstr = dst;
    }else{
        if (NULL != dst) {
            efree(dst);
        }
    }
    return newstr;
}

char*   
xstrappend_nofree(char *dst, char *src, int srclen)
{
    char    *newstr;
    int     len;
    int     size; 
    
    if (NULL == dst) {
        len = 0;
    }else{
        len = strlen(dst);
    }
    size = len + srclen;

    newstr = emalloc(size + 1);
    if (NULL == newstr)
        return NULL;
    
    if (NULL != dst) {
        strcpy(newstr, dst);
    }
    strncpy(newstr+len, src, srclen);
    newstr[size] = 0;
    //efree(dst);

    return newstr;
}


char*   
xstrnchr(const char *src, int srclen, char fc)
{
    int     i;

    if (NULL == src || 0 >= srclen)
        return NULL;
    INFO("xstrnchr: %d\n", srclen); 
    for (i = 0; i < srclen; i++) {
        if (src[i] == fc)
            return src + i;
    }

    return NULL;
}

int
text_decode(char *newstr, char* text, char *code)
{
    char    *srcstr;
    char    *tmpstr;
    char    *find, *start, *end;
    int     textlen, newstrlen;
    int     i = 0, ei = 0, size;
    char    encode[32] = {0};  // 语言编码
    char    bq; // 编码是base64还是quoted-printable
    int     cpsize, dlen;

    if (NULL == text)
        return -1;
  
    INFO("decode: %s\n", text);
    textlen = strlen(text);
    newstrlen = 2 * textlen;
    tmpstr = emalloc(newstrlen + 1);
    INFO("tmpstr: %p\n", tmpstr); 
    srcstr = text;
    while (1)
    {
        /*
        if (NULL == newstr) {
            newstr = emalloc(textlen+1);
            memset(newstr, 0, textlen+1);
        }*/

        INFO("i = %d\n", i);
        find = strstr(srcstr, "=?");
        if (NULL == find) {
            // 如果曾经找到过的话，必须复制后面的数据的
            INFO(" not found =? srcstr: %p, end: %p\n", srcstr, end);
            if (srcstr >= text) {
                int csize;
                char    cch;

                size = (text + textlen) - srcstr;
                for (csize = 0; csize < size; csize++) {
                    cch = srcstr[csize];
                    if (cch != '\r' && cch != '\n' && cch != ' ') {
                        newstr[i] = srcstr[csize];
                        i++;
                    }
                }
                //strncpy(newstr+i, srcstr, size);
                //i += size;
                newstr[i] = 0;
            }
            break;
        }
        INFO("find1: %s\n", find);
        
        // 这个有可能是有问题的，比如=?GB2312?Q?=BB=B6=D3=AD=BC=D3=C8=EB=D6=D0=B9=FA=D6=C6=D4=EC=CD=F8=28Made?=
        end = strstr(srcstr, "?=");
        if (NULL == end) {
            // 如果曾经找到过的话，必须复制后面的数据的
            if (srcstr >= text) {
                int     csize;
                char    cch;
                size = (text + textlen) - srcstr;
                for (csize = 0; csize < size; csize++) {
                    cch = srcstr[csize];
                    if (cch != '\r' && cch != '\n' && cch != ' ') {
                        newstr[i] = srcstr[csize];
                        i++;
                    }
                }

                //strncpy(newstr+i, srcstr, size);
                //i += size;
            }
            break;
        }
        
        INFO("find2: %s\n", end);
        // 说明=?之前还有字符，直接copy过来
        if (find > srcstr) {
            start = srcstr;
            while (start < find) {
                if (*start != '\r' && *start  != '\n') {
                    newstr[i] = *start;
                    INFO("copy %c\n", *start);
                    i++;
                }
                start++;
            }
        }
        INFO("=== newstr: %s\n", newstr);
        // 跳过=?
        find += 2;
        // 获取到语言编码
        ei = 0;
        while (*find && *find != '?') {
            if (*find >= 'a' && *find <= 'z') {
                encode[ei] = *find - 32;
            }else{
                encode[ei] = *find;
            }
            find++;
            ei++;
        }
        // 必须是?
        if (*find != '?') {
            SAFE_FREE(newstr);
            break;
        }
        find++;
        // 获取到传输编码
        bq = (*find >= 'a')? *find: *find+32;
        find += 2;
        
        if (end <= find) {
            end = strstr(find, "?=");
            if (NULL == end) {
                // 如果曾经找到过的话，就当不完整处理，直接到最后
                end = text + textlen;
                break;
            }

        }
        cpsize = end-find;
        INFO("bq: %c, find: %p,%s end: %p, len: %d\n", bq, find, find, end, end-find);
        if (bq == 'b') {
            dlen = base64_decode(tmpstr, find, end-find, 0);
            tmpstr[dlen] = 0;
        }else if (bq == 'q') {
            dlen = qp_decode(tmpstr, find, end-find);
            tmpstr[dlen] = 0;
        }else{
            strncpy(tmpstr, find, cpsize); 
            tmpstr[cpsize] = 0;
        }
        
        INFO("code: %s, encode: %s, tmpstr: %s, newstr: %s\n", code, encode, tmpstr, newstr); 
        if (strcmp(code, encode) == 0) {
            strcpy(newstr+i, tmpstr);
            i += strlen(tmpstr);
        }else{
            // 语言编码不一样的话就应该要转码了
            cpsize = convert_string(encode, code, newstr+i, newstrlen-i, tmpstr, end-find);
            i += cpsize;
        }
        INFO("111 newstr: %s\n", newstr);
    
        srcstr = end + 2;
    }
     
    INFO("tmpstr: %p\n", tmpstr); 
    efree(tmpstr);
    newstr[i] = 0;

    return i;
}


int
isfile(char *filename)          /* Is file, not directory */
{
    struct stat buf;
    if (stat(filename, &buf) != 0)
        return 0;
    if (!S_ISREG(buf.st_mode))
        return 0;
    return 1;
}

int
isdir(char *filename)                   /* Is directory */
{
    struct stat buf;
    if (stat(filename, &buf) != 0)
        return 0;
    if (!S_ISDIR(buf.st_mode))
        return 0;
    return 1;
}


char
check_maintype(char *content)
{
    char ctype;

    if (strstr(content, "text/") != NULL) {
        ctype = 't';
    }else if (strstr(content, "multipart/") != NULL) {
        ctype = 'm';
    }else if (strstr(content, "application/") != NULL) {
        ctype = 'a';
    }else if (strstr(content, "image/") != NULL) {
        ctype = 'i';
    }else if (strstr(content, "audio/") != NULL) {
        ctype = 'u';
    }else if (strstr(content, "chemical/") != NULL) {
        ctype = 'c';
    }else if (strstr(content, "message/") != NULL) {
        ctype = 'e';
    }else if (strstr(content, "model/") != NULL) {
        ctype = 'o';
    }else if (strstr(content, "video/") != NULL) {
        ctype = 'v';
    }else{
        ctype = 0;
    }
    return ctype;
}

/*!
 */
int 
file_range_decode(char *mailfile, int offset, int len, char tencode, char *save)
{
    int     ret = 0;
    FILE    *fp;
    BUFFER  *buf = NULL;
    char    rbuf[4096+1];
    int     rlen = 0, last = 0, dlen = 0;
    char    *tmp;
    char    *savepos;
    int     savelen = 0;
    int     readsize = 0; // 已经从文件中读取的字节数

    if (NULL == mailfile)
        return -1;
    if (0 >= len)
        return -2;
    if (NULL == save)
        return -3;

    fp = fopen(mailfile, "r");
    if (NULL == fp)
        return -4;
    
    // 有内容，应该是保存的文件名
    if (*save != 0) {
        buf = buf_new(4096, save, 1);
    }
    
    INFO("buf save: %s\n", save);
    rlen = 4096;
    fseek(fp, offset, SEEK_SET);
    while (1) {
        // 读取一行
        tmp = fgets(rbuf+last, rlen, fp);
        if (NULL != tmp) {
            int readlen = strlen(tmp);
            readsize += readlen;
            if (readsize >= len) {
                readlen -= (readsize-len);
            }

            if (tmp[readlen-2] == '\r') {
                readlen -= 2;
            }else if (tmp[readlen-1] == '\n' || tmp[readlen-1] == '\r') {
                readlen --;
            }

            last += readlen;
            rlen -= readlen;
        }
        if ('b' == tencode) { // base64编码
            INFO("rlen: %d, last: %d \n", rlen, last);
            if ((0 == rlen || readsize >=len || NULL == tmp) && last > 0) {
                if (NULL == buf) {
                    savepos = save + savelen;
                }else{
                    savepos = buf->data;
                }

                dlen = base64_decode(savepos, rbuf, last, 0);
                
                last = 0;
                rlen = 4096;
                savepos += dlen;
                if (NULL != buf) {
                    buf->pos += dlen;
                    buf_write_file(buf);
                }
            }
        }else if ('q' == tencode) { // quoted-printable 编码
            if (NULL == buf) {
                savepos = save + savelen;
            }else{
                savepos = buf->data;
            }

            dlen = qp_decode(savepos, rbuf, last);

            last = 0;
            rlen = 4096;
            savepos += dlen;
            if (NULL != buf) {
                buf->pos += dlen;
                buf_write_file(buf);
            }
        }else{ // 没有编码，不用处理了,
            ret = -5;
            goto file_range_decode_over;
        }

        if (readsize >= len || NULL == tmp)
            break;
    }
    
file_range_decode_over: 
    if (NULL != buf) {
        buf_delete(buf);
    }
    fclose(fp);
    return ret;
}



#ifdef MAIN_TEST_UTIL
GHashTable  *gmemhash;

int
main()
{
    //char    key[64], value[512]; 
    //char    *test = "Content-Type: multipart/mixed;boundary=\"---------=_plZefGJyzGprTPgpIiimnMLgnWyAdYYQkwVqdF\";charset=\"gb2312\"";
    //char    *ret;
    //int     iret;

    //printf("%s\n", test);

    /*
    ret = fields_get_pair(test, key, value, "type");
    printf("key=%s, value=%s\n", key, value);

    ret = fields_get_pair(ret, key, value, "type");
    printf("key=%s, value=%s\n", key, value);
    
    ret = fields_get_pair(ret, key, value, "type");
    printf("key=%s, value=%s\n", key, value);
    */
    
    /*
    printf("----------------------------------------------\n");
    iret = fields_get_pairs(test, "type", NULL, contenttype_set);
    printf("iret=%d\n", iret);
    */

    char    *test = "=?gb2312?b?s0xuimir19s2r8jzsoxptc2zvlzk9cu1w/fk6s5yyxi=?=";
    char    buffer[2048];

    gmemhash = e_init(NULL);
    printf("orig: %s\n", test);

    text_decode(buffer, test, "GB2312");
    
    printf("decode: %s\n", buffer);
    
    e_destroy(gmemhash);
    return 0;
}


#endif


